mirror of
https://github.com/holub/mame
synced 2025-04-16 21:44:32 +03:00
cpu: Allow recompilers to work with W^X policy
This commit is contained in:
parent
7b22d972ae
commit
4eca05fe67
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?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" />
|
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="MAME" type="win32" />
|
||||||
<description>MAME</description>
|
<description>MAME</description>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?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" />
|
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="MESS" type="win32" />
|
||||||
<description>MESS</description>
|
<description>MESS</description>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -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)));
|
label_fixup *fixup = reinterpret_cast<label_fixup *>(m_cache.alloc(sizeof(*fixup)));
|
||||||
new (fixup) label_fixup{ nullptr, curlabel, callback };
|
new (fixup) label_fixup{ nullptr, curlabel, callback };
|
||||||
m_fixup_list.append(*fixup);
|
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;
|
return curlabel->m_codeptr;
|
||||||
|
@ -11,15 +11,22 @@
|
|||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "drccache.h"
|
#include "drccache.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
//**************************************************************************
|
namespace {
|
||||||
// MACROS
|
|
||||||
//**************************************************************************
|
|
||||||
|
|
||||||
// ensure that all memory allocated is aligned to an 8-byte boundary
|
template <typename T, typename U> constexpr T *ALIGN_PTR_UP(T *p, U align)
|
||||||
#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)))
|
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 - constructor
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
drc_cache::drc_cache(size_t bytes)
|
drc_cache::drc_cache(size_t bytes) :
|
||||||
: m_near((drccodeptr)osd_alloc_executable(bytes)),
|
m_cache({ NEAR_CACHE_SIZE, bytes - NEAR_CACHE_SIZE }),
|
||||||
m_neartop(m_near),
|
m_near(reinterpret_cast<drccodeptr>(m_cache.get())),
|
||||||
m_base(m_near + NEAR_CACHE_SIZE),
|
m_neartop(m_near),
|
||||||
m_top(m_base),
|
m_base(ALIGN_PTR_UP(m_near + NEAR_CACHE_SIZE, m_cache.page_size())),
|
||||||
m_end(m_near + bytes),
|
m_top(m_base),
|
||||||
m_codegen(nullptr),
|
m_limit(m_near + m_cache.size()),
|
||||||
m_size(bytes)
|
m_end(m_limit),
|
||||||
|
m_codegen(nullptr),
|
||||||
|
m_size(m_cache.size())
|
||||||
{
|
{
|
||||||
memset(m_free, 0, sizeof(m_free));
|
// alignment and page size must be powers of two, cache must be page-aligned
|
||||||
memset(m_nearfree, 0, sizeof(m_nearfree));
|
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()
|
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()
|
void drc_cache::flush()
|
||||||
{
|
{
|
||||||
// can't flush in the middle of codegen
|
// 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
|
// just reset the top back to the base and re-seed
|
||||||
m_top = m_base;
|
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
|
// pick first from the free list
|
||||||
if (bytes < MAX_PERMANENT_ALLOC)
|
if (bytes < MAX_PERMANENT_ALLOC)
|
||||||
{
|
{
|
||||||
free_link **linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
free_link **const linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||||
free_link *link = *linkptr;
|
free_link *const link = *linkptr;
|
||||||
if (link != nullptr)
|
if (link)
|
||||||
{
|
{
|
||||||
*linkptr = link->m_next;
|
*linkptr = link->m_next;
|
||||||
return link;
|
return link;
|
||||||
@ -93,11 +109,13 @@ void *drc_cache::alloc(size_t bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if no space, we just fail
|
// if no space, we just fail
|
||||||
drccodeptr ptr = (drccodeptr)ALIGN_PTR_DOWN(m_end - bytes);
|
drccodeptr const ptr = ALIGN_PTR_DOWN(m_end - bytes, CACHE_ALIGNMENT);
|
||||||
if (m_top > ptr)
|
drccodeptr const limit = ALIGN_PTR_DOWN(ptr, m_cache.page_size());
|
||||||
|
if (m_top > limit)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// otherwise update the end of the cache
|
// otherwise update the end of the cache
|
||||||
|
m_limit = limit;
|
||||||
m_end = ptr;
|
m_end = ptr;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@ -115,9 +133,9 @@ void *drc_cache::alloc_near(size_t bytes)
|
|||||||
// pick first from the free list
|
// pick first from the free list
|
||||||
if (bytes < MAX_PERMANENT_ALLOC)
|
if (bytes < MAX_PERMANENT_ALLOC)
|
||||||
{
|
{
|
||||||
free_link **linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
free_link **const linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||||
free_link *link = *linkptr;
|
free_link *const link = *linkptr;
|
||||||
if (link != nullptr)
|
if (link)
|
||||||
{
|
{
|
||||||
*linkptr = link->m_next;
|
*linkptr = link->m_next;
|
||||||
return link;
|
return link;
|
||||||
@ -125,8 +143,8 @@ void *drc_cache::alloc_near(size_t bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if no space, we just fail
|
// if no space, we just fail
|
||||||
drccodeptr ptr = (drccodeptr)ALIGN_PTR_UP(m_neartop);
|
drccodeptr const ptr = ALIGN_PTR_UP(m_neartop, CACHE_ALIGNMENT);
|
||||||
if (ptr + bytes > m_base)
|
if ((ptr + bytes) > m_base)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// otherwise update the top of the near part of the cache
|
// 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)
|
void *drc_cache::alloc_temporary(size_t bytes)
|
||||||
{
|
{
|
||||||
// can't allocate in the middle of codegen
|
// can't allocate in the middle of codegen
|
||||||
assert(m_codegen == nullptr);
|
assert(!m_codegen);
|
||||||
|
|
||||||
// if no space, we just fail
|
// if no space, we just fail
|
||||||
drccodeptr ptr = m_top;
|
drccodeptr const ptr = m_top;
|
||||||
if (ptr + bytes >= m_end)
|
if ((ptr + bytes) > m_limit)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// otherwise, update the cache top
|
// 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;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,23 +182,32 @@ void *drc_cache::alloc_temporary(size_t bytes)
|
|||||||
|
|
||||||
void drc_cache::dealloc(void *memory, 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(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
|
// determine which free list to add to
|
||||||
free_link **linkptr;
|
free_link **const linkptr = &((mem < m_base) ? m_nearfree : m_free)[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||||
if ((drccodeptr)memory < m_base)
|
|
||||||
linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
|
||||||
else
|
|
||||||
linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
|
||||||
|
|
||||||
// link is into the free list for our size
|
// 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;
|
link->m_next = *linkptr;
|
||||||
*linkptr = link;
|
*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
|
// 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)
|
drccodeptr *drc_cache::begin_codegen(uint32_t reserve_bytes)
|
||||||
{
|
{
|
||||||
// can't restart in the middle of codegen
|
// can't restart in the middle of codegen
|
||||||
assert(m_codegen == nullptr);
|
assert(!m_codegen);
|
||||||
assert(m_ooblist.first() == nullptr);
|
assert(m_oob_list.empty());
|
||||||
|
|
||||||
// if still no space, we just fail
|
// if no space, we just fail
|
||||||
drccodeptr ptr = m_top;
|
if ((m_top + reserve_bytes) > m_limit)
|
||||||
if (ptr + reserve_bytes >= m_end)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// otherwise, return a pointer to the cache top
|
// 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;
|
m_codegen = m_top;
|
||||||
return &m_top;
|
return &m_top;
|
||||||
}
|
}
|
||||||
@ -207,23 +235,22 @@ drccodeptr *drc_cache::begin_codegen(uint32_t reserve_bytes)
|
|||||||
|
|
||||||
drccodeptr drc_cache::end_codegen()
|
drccodeptr drc_cache::end_codegen()
|
||||||
{
|
{
|
||||||
drccodeptr result = m_codegen;
|
drccodeptr const result = m_codegen;
|
||||||
|
|
||||||
// run the OOB handlers
|
// run the OOB handlers
|
||||||
oob_handler *oob;
|
while (!m_oob_list.empty())
|
||||||
while ((oob = m_ooblist.detach_head()) != nullptr)
|
|
||||||
{
|
{
|
||||||
// call the callback
|
// call the callback
|
||||||
oob->m_callback(&m_top, oob->m_param1, oob->m_param2);
|
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);
|
assert((m_top - m_codegen) < CODEGEN_MAX_BYTES);
|
||||||
|
|
||||||
// release our memory
|
// add it to the free list
|
||||||
oob->~oob_handler();
|
m_oob_free.splice(m_oob_free.begin(), m_oob_list, m_oob_list.begin());
|
||||||
dealloc(oob, sizeof(*oob));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the cache top
|
// 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;
|
m_codegen = nullptr;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -235,20 +262,24 @@ drccodeptr drc_cache::end_codegen()
|
|||||||
// out-of-band 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
|
// pull an item from the free list
|
||||||
oob_handler *oob = (oob_handler *)alloc(sizeof(*oob));
|
std::list<oob_handler>::iterator oob;
|
||||||
assert(oob != nullptr);
|
if (m_oob_free.empty())
|
||||||
new (oob) oob_handler();
|
{
|
||||||
|
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
|
// fill it in
|
||||||
oob->m_callback = std::move(callback);
|
oob->m_callback = std::move(callback);
|
||||||
oob->m_param1 = param1;
|
oob->m_param1 = param1;
|
||||||
oob->m_param2 = param2;
|
oob->m_param2 = param2;
|
||||||
|
|
||||||
// add to the tail
|
|
||||||
m_ooblist.append(*oob);
|
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
Universal dynamic recompiler cache management.
|
Universal dynamic recompiler cache management.
|
||||||
|
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#ifndef MAME_CPU_DRCCACHE_H
|
||||||
|
#define MAME_CPU_DRCCACHE_H
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef __DRCCACHE_H__
|
#include "modules/lib/osdlib.h"
|
||||||
#define __DRCCACHE_H__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
@ -63,43 +63,46 @@ public:
|
|||||||
void dealloc(void *memory, size_t bytes);
|
void dealloc(void *memory, size_t bytes);
|
||||||
|
|
||||||
// codegen helpers
|
// codegen helpers
|
||||||
|
void codegen_init();
|
||||||
|
void codegen_complete();
|
||||||
drccodeptr *begin_codegen(uint32_t reserve_bytes);
|
drccodeptr *begin_codegen(uint32_t reserve_bytes);
|
||||||
drccodeptr end_codegen();
|
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:
|
private:
|
||||||
// largest block of code that can be generated at once
|
// 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)
|
// 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
|
// 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
|
// 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
|
// core parameters
|
||||||
drccodeptr m_near; // pointer to the near part of the cache
|
drccodeptr const m_near; // pointer to the near part of the cache
|
||||||
drccodeptr m_neartop; // top of the near part of the cache
|
drccodeptr m_neartop; // unallocated area of near cache
|
||||||
drccodeptr m_base; // base pointer to the compiler cache
|
drccodeptr const m_base; // end of near cache
|
||||||
drccodeptr m_top; // current top of cache
|
drccodeptr m_top; // end of temporary allocations and code
|
||||||
drccodeptr m_end; // end of cache memory
|
drccodeptr m_limit; // limit for temporary allocations and code (page-aligned)
|
||||||
drccodeptr m_codegen; // start of generated code
|
drccodeptr m_end; // first allocated byte in cache
|
||||||
size_t m_size; // size of the cache in bytes
|
drccodeptr m_codegen; // start of current generated code block
|
||||||
|
size_t const m_size; // size of the cache in bytes
|
||||||
|
|
||||||
// oob management
|
// oob management
|
||||||
struct oob_handler
|
struct oob_handler
|
||||||
{
|
{
|
||||||
oob_handler *next() const { return m_next; }
|
drc_oob_delegate m_callback; // callback function
|
||||||
|
void * m_param1; // 1st pointer parameter
|
||||||
oob_handler * m_next; // next handler
|
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
|
// free lists
|
||||||
struct free_link
|
struct free_link
|
||||||
@ -110,5 +113,4 @@ private:
|
|||||||
free_link * m_nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
|
free_link * m_nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // MAME_CPU_DRCCACHE_H
|
||||||
#endif /* __DRCCACHE_H__ */
|
|
||||||
|
@ -348,7 +348,9 @@ void drcuml_block::end()
|
|||||||
disassemble();
|
disassemble();
|
||||||
|
|
||||||
// generate the code via the back-end
|
// generate the code via the back-end
|
||||||
|
m_drcuml.cache().codegen_init();
|
||||||
m_drcuml.generate(*this, &m_inst[0], m_nextinst);
|
m_drcuml.generate(*this, &m_inst[0], m_nextinst);
|
||||||
|
m_drcuml.cache().codegen_complete();
|
||||||
|
|
||||||
// block is no longer in use
|
// block is no longer in use
|
||||||
m_inuse = false;
|
m_inuse = false;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#ifndef __OSDLIB__
|
#ifndef __OSDLIB__
|
||||||
#define __OSDLIB__
|
#define __OSDLIB__
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -58,6 +59,90 @@ int osd_setenv(const char *name, const char *value, int overwrite);
|
|||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
std::string osd_get_clipboard_text(void);
|
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
|
dynamic_module: load functions from optional shared libraries
|
||||||
|
|
||||||
@ -69,7 +154,6 @@ std::string osd_get_clipboard_text(void);
|
|||||||
revisions of a same library)
|
revisions of a same library)
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
namespace osd {
|
|
||||||
class dynamic_module
|
class dynamic_module
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -80,7 +164,7 @@ public:
|
|||||||
virtual ~dynamic_module() { };
|
virtual ~dynamic_module() { };
|
||||||
|
|
||||||
template <typename T>
|
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));
|
return reinterpret_cast<T>(get_symbol_address(symbol));
|
||||||
}
|
}
|
||||||
|
@ -8,26 +8,26 @@
|
|||||||
//
|
//
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
#include <cstdlib>
|
// MAME headers
|
||||||
#include <unistd.h>
|
#include "osdcore.h"
|
||||||
#include <sys/mman.h>
|
#include "osdlib.h"
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <csignal>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <memory>
|
#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.h>
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
|
|
||||||
// MAME headers
|
|
||||||
#include "osdcore.h"
|
|
||||||
#include "osdlib.h"
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// osd_getenv
|
// osd_getenv
|
||||||
@ -56,42 +56,6 @@ void osd_process_kill()
|
|||||||
kill(getpid(), SIGKILL);
|
kill(getpid(), SIGKILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================
|
|
||||||
// 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
|
// osd_break_into_debugger
|
||||||
//============================================================
|
//============================================================
|
||||||
@ -202,25 +166,23 @@ int osd_getpid(void)
|
|||||||
return getpid();
|
return getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================
|
|
||||||
// dynamic_module_posix_impl
|
|
||||||
//============================================================
|
|
||||||
|
|
||||||
namespace osd {
|
namespace osd {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
class dynamic_module_posix_impl : public dynamic_module
|
class dynamic_module_posix_impl : public dynamic_module
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
dynamic_module_posix_impl(std::vector<std::string> &libraries)
|
dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
|
||||||
: m_module(nullptr)
|
|
||||||
{
|
{
|
||||||
m_libraries = libraries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~dynamic_module_posix_impl() override
|
virtual ~dynamic_module_posix_impl() override
|
||||||
{
|
{
|
||||||
if (m_module != nullptr)
|
if (m_module)
|
||||||
dlclose(m_module);
|
dlclose(m_module);
|
||||||
};
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual generic_fptr_t get_symbol_address(char const *symbol) override
|
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
|
* one of them, all additional symbols will be loaded from the same library
|
||||||
*/
|
*/
|
||||||
if (m_module)
|
if (m_module)
|
||||||
{
|
|
||||||
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
|
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &library : m_libraries)
|
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)
|
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;
|
m_module = module;
|
||||||
return function;
|
return function;
|
||||||
@ -259,12 +219,61 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_libraries;
|
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)
|
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
|
} // namespace osd
|
||||||
|
@ -8,24 +8,24 @@
|
|||||||
//
|
//
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <csignal>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
// MAME headers
|
// MAME headers
|
||||||
#include "osdcore.h"
|
#include "osdcore.h"
|
||||||
#include "osdlib.h"
|
#include "osdlib.h"
|
||||||
|
|
||||||
#include <SDL2/SDL.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>
|
||||||
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// osd_getenv
|
// osd_getenv
|
||||||
//============================================================
|
//============================================================
|
||||||
@ -53,37 +53,6 @@ void osd_process_kill()
|
|||||||
kill(getpid(), SIGKILL);
|
kill(getpid(), SIGKILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================
|
|
||||||
// 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
|
// osd_break_into_debugger
|
||||||
//============================================================
|
//============================================================
|
||||||
@ -133,25 +102,23 @@ int osd_getpid(void)
|
|||||||
return getpid();
|
return getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================
|
|
||||||
// dynamic_module_posix_impl
|
|
||||||
//============================================================
|
|
||||||
|
|
||||||
namespace osd {
|
namespace osd {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
class dynamic_module_posix_impl : public dynamic_module
|
class dynamic_module_posix_impl : public dynamic_module
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
dynamic_module_posix_impl(std::vector<std::string> &libraries)
|
dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
|
||||||
: m_module(nullptr)
|
|
||||||
{
|
{
|
||||||
m_libraries = libraries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~dynamic_module_posix_impl() override
|
virtual ~dynamic_module_posix_impl() override
|
||||||
{
|
{
|
||||||
if (m_module != nullptr)
|
if (m_module)
|
||||||
dlclose(m_module);
|
dlclose(m_module);
|
||||||
};
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual generic_fptr_t get_symbol_address(char const *symbol) override
|
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
|
* one of them, all additional symbols will be loaded from the same library
|
||||||
*/
|
*/
|
||||||
if (m_module)
|
if (m_module)
|
||||||
{
|
|
||||||
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
|
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &library : m_libraries)
|
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)
|
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;
|
m_module = module;
|
||||||
return function;
|
return function;
|
||||||
@ -190,12 +155,67 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_libraries;
|
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)
|
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
|
} // namespace osd
|
||||||
|
@ -8,30 +8,27 @@
|
|||||||
//
|
//
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mmsystem.h>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
// MAME headers
|
// MAME headers
|
||||||
#include "osdlib.h"
|
#include "osdlib.h"
|
||||||
#include "osdcomm.h"
|
#include "osdcomm.h"
|
||||||
#include "osdcore.h"
|
#include "osdcore.h"
|
||||||
#include "strconv.h"
|
#include "strconv.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <memoryapi.h>
|
||||||
|
|
||||||
#include <wrl\client.h>
|
#include <wrl\client.h>
|
||||||
|
|
||||||
#include "strconv.h"
|
|
||||||
|
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace Windows::ApplicationModel::DataTransfer;
|
using namespace Windows::ApplicationModel::DataTransfer;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// GLOBAL VARIABLES
|
// GLOBAL VARIABLES
|
||||||
@ -88,30 +85,6 @@ void osd_process_kill()
|
|||||||
TerminateProcess(GetCurrentProcess(), -1);
|
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 nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================
|
|
||||||
// osd_free_executable
|
|
||||||
//
|
|
||||||
// frees memory allocated with osd_alloc_executable
|
|
||||||
//============================================================
|
|
||||||
|
|
||||||
void osd_free_executable(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// osd_break_into_debugger
|
// osd_break_into_debugger
|
||||||
//============================================================
|
//============================================================
|
||||||
@ -188,3 +161,47 @@ int osd_getpid(void)
|
|||||||
return GetCurrentProcessId();
|
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
|
||||||
|
@ -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
|
// MAME headers
|
||||||
#include "osdlib.h"
|
#include "osdlib.h"
|
||||||
#include "osdcomm.h"
|
#include "osdcomm.h"
|
||||||
@ -29,6 +18,17 @@
|
|||||||
#include "winutf8.h"
|
#include "winutf8.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <memoryapi.h>
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
// GLOBAL VARIABLES
|
// GLOBAL VARIABLES
|
||||||
//============================================================
|
//============================================================
|
||||||
@ -82,30 +82,6 @@ void osd_process_kill()
|
|||||||
TerminateProcess(GetCurrentProcess(), -1);
|
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
|
// osd_break_into_debugger
|
||||||
@ -228,20 +204,21 @@ int osd_getpid()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace osd {
|
namespace osd {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
class dynamic_module_win32_impl : public dynamic_module
|
class dynamic_module_win32_impl : public dynamic_module
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
dynamic_module_win32_impl(std::vector<std::string> &libraries)
|
dynamic_module_win32_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
|
||||||
: m_module(nullptr)
|
|
||||||
{
|
{
|
||||||
m_libraries = libraries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~dynamic_module_win32_impl() override
|
virtual ~dynamic_module_win32_impl() override
|
||||||
{
|
{
|
||||||
if (m_module != nullptr)
|
if (m_module)
|
||||||
FreeLibrary(m_module);
|
FreeLibrary(m_module);
|
||||||
};
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual generic_fptr_t get_symbol_address(char const *symbol) override
|
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
|
* one of them, all additional symbols will be loaded from the same library
|
||||||
*/
|
*/
|
||||||
if (m_module)
|
if (m_module)
|
||||||
{
|
|
||||||
return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol));
|
return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol));
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &library : m_libraries)
|
for (auto const &library : m_libraries)
|
||||||
{
|
{
|
||||||
osd::text::tstring tempstr = osd::text::to_tstring(library);
|
osd::text::tstring const tempstr = osd::text::to_tstring(library);
|
||||||
HMODULE module = load_library(tempstr.c_str());
|
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;
|
m_module = module;
|
||||||
return function;
|
return function;
|
||||||
@ -281,12 +256,56 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_libraries;
|
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)
|
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
|
} // namespace osd
|
||||||
|
@ -342,27 +342,6 @@ void osd_work_item_release(osd_work_item *item);
|
|||||||
MISCELLANEOUS INTERFACES
|
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
|
/// \brief Break into host debugger if attached
|
||||||
///
|
///
|
||||||
/// This function is called when a fatal error occurs. If a debugger is
|
/// This function is called when a fatal error occurs. If a debugger is
|
||||||
|
Loading…
Reference in New Issue
Block a user