Merge pull request #1598 from davidgfnet/vmemstuff2

Implement a separate API for nvmem
This commit is contained in:
David G. F 2019-05-12 16:34:55 +02:00 committed by GitHub
commit a0c725be4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 449 additions and 511 deletions

View File

@ -13,7 +13,7 @@
#include <time.h>
VArray2 aica_ram;
VLockedMemory aica_ram;
u32 VREG;//video reg =P
u32 ARMRST;//arm reset reg
u32 rtc_EN=0;

View File

@ -2,7 +2,7 @@
#include "types.h"
extern u32 VREG;
extern VArray2 aica_ram;
extern VLockedMemory aica_ram;
extern u32 RealTimeClock;
u32 ReadMem_aica_rtc(u32 addr,u32 sz);
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);

View File

@ -21,7 +21,6 @@ _vmem_WriteMem32FP* _vmem_WF32[HANDLER_COUNT];
//upper 8b of the address
void* _vmem_MemInfo_ptr[0x100];
void _vmem_get_ptrs(u32 sz,bool write,void*** vmap,void*** func)
{
*vmap=_vmem_MemInfo_ptr;
@ -385,10 +384,7 @@ void _vmem_reset()
verify(_vmem_register_handler(0,0,0,0,0,0)==0);
}
void _vmem_term()
{
}
void _vmem_term() {}
#include "hw/pvr/pvr_mem.h"
#include "hw/sh4/sh4_mem.h"
@ -409,414 +405,119 @@ void* malloc_pages(size_t size) {
#endif
}
bool _vmem_reserve_nonvmem()
{
virt_ram_base = 0;
p_sh4rcb=(Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
mem_b.size=RAM_SIZE;
mem_b.data=(u8*)malloc_pages(RAM_SIZE);
vram.size=VRAM_SIZE;
vram.data=(u8*)malloc_pages(VRAM_SIZE);
aica_ram.size=ARAM_SIZE;
aica_ram.data=(u8*)malloc_pages(ARAM_SIZE);
return true;
}
void _vmem_bm_reset_nvmem();
// Resets the FPCB table (by either clearing it to the default val
// or by flushing it and making it fault on access again.
void _vmem_bm_reset() {
if (virt_ram_base) {
#if !defined(TARGET_NO_NVMEM)
_vmem_bm_reset_nvmem();
#endif
}
#ifndef TARGET_IPHONE
if (!virt_ram_base)
#endif
{
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, FPCB_SIZE);
}
// If we allocated it via vmem:
if (virt_ram_base)
vmem_platform_reset_mem(p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
else
// We allocated it via a regular malloc/new/whatever on the heap
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
}
static void _vmem_release_nonvmem()
{
free(p_sh4rcb);
free(vram.data);
free(aica_ram.data);
free(mem_b.data);
}
// This gets called whenever there is a pagefault, it is possible that it lands
// on the fpcb memory range, which is allocated on miss. Returning true tells the
// fault handler this was us, and that the page is resolved and can continue the execution.
bool BM_LockedWrite(u8* address) {
if (!virt_ram_base)
return false; // No vmem, therefore not us who caused this.
#if !defined(TARGET_NO_NVMEM)
uintptr_t ptrint = (uintptr_t)address;
uintptr_t start = (uintptr_t)p_sh4rcb->fpcb;
uintptr_t end = start + sizeof(p_sh4rcb->fpcb);
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
#if HOST_OS==OS_WINDOWS
#include <Windows.h>
HANDLE mem_handle;
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
{
void* ptr;
void* rv;
u32 map_times=addrsz/size;
verify((addrsz%size)==0);
verify(map_times>=1);
rv= MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
if (!rv)
return 0;
for (u32 i=1;i<map_times;i++)
{
dst+=size;
ptr=MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
if (!ptr) return 0;
}
return rv;
}
void* _nvmem_unused_buffer(u32 start,u32 end)
{
void* ptr=VirtualAlloc(&virt_ram_base[start],end-start,MEM_RESERVE,PAGE_NOACCESS);
if (ptr == 0)
return 0;
return ptr;
}
void* _nvmem_alloc_mem()
{
mem_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX, 0);
void* rv= (u8*)VirtualAlloc(0, 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX, MEM_RESERVE, PAGE_NOACCESS);
if (rv) VirtualFree(rv,0,MEM_RELEASE);
return rv;
}
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
#endif
#ifdef _ANDROID
#include <linux/ashmem.h>
#ifndef ASHMEM_DEVICE
#define ASHMEM_DEVICE "/dev/ashmem"
#endif
int ashmem_create_region(const char *name, size_t size)
{
int fd, ret;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
if (name) {
char buf[ASHMEM_NAME_LEN];
strlcpy(buf, name, sizeof(buf));
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
if (ret < 0)
goto error;
}
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0)
goto error;
return fd;
error:
close(fd);
return ret;
}
#endif
int fd;
void* _nvmem_unused_buffer(u32 start,u32 end)
{
void* ptr=mmap(&virt_ram_base[start], end-start, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
if (MAP_FAILED==ptr)
return 0;
return ptr;
}
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
{
void* ptr;
void* rv;
printf("MAP %08X w/ %d\n",dst,offset);
u32 map_times=addrsz/size;
verify((addrsz%size)==0);
verify(map_times>=1);
u32 prot=PROT_READ|(w?PROT_WRITE:0);
rv= mmap(&virt_ram_base[dst], size, prot, MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
if (MAP_FAILED==rv || rv!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
{
printf("MAP1 failed %d\n",errno);
return 0;
}
for (u32 i=1;i<map_times;i++)
{
dst+=size;
ptr=mmap(&virt_ram_base[dst], size, prot , MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
if (MAP_FAILED==ptr || ptr!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
{
printf("MAP2 failed %d\n",errno);
return 0;
}
}
return rv;
}
void* _nvmem_alloc_mem()
{
#if HOST_OS == OS_DARWIN
string path = get_writable_data_path("/dcnzorz_mem");
fd = open(path.c_str(),O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink(path.c_str());
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
#elif !defined(_ANDROID)
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
shm_unlink("/dcnzorz_mem");
if (fd==-1)
{
fd = open("dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink("dcnzorz_mem");
}
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
#else
fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
if (false)//this causes writebacks to flash -> slow and stuttery
{
fd = open("/data/data/com.reicast.emulator/files/dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink("/data/data/com.reicast.emulator/files/dcnzorz_mem");
}
#endif
u32 sz = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
void* rv=mmap(0, sz, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
verify(rv != NULL);
munmap(rv,sz);
return (u8*)rv + 0x10000 - unat(rv)%0x10000;//align to 64 KB (Needed for linaro mmap not to extend to next region)
}
#endif
#define map_buffer(dsts,dste,offset,sz,w) {ptr=_nvmem_map_buffer(dsts,dste-dsts,offset,sz,w);if (!ptr) return false;}
#define unused_buffer(start,end) {ptr=_nvmem_unused_buffer(start,end);if (!ptr) return false;}
u32 pagecnt;
void _vmem_bm_reset_nvmem()
{
#if defined(TARGET_NO_NVMEM)
return;
#endif
#ifdef TARGET_IPHONE
//On iOS & nacl we allways allocate all of the mapping table
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_READ | PROT_WRITE);
return;
#endif
pagecnt=0;
#if HOST_OS==OS_WINDOWS
VirtualFree(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MEM_DECOMMIT);
#else
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_NONE);
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_DONTNEED);
#ifdef MADV_REMOVE
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_REMOVE);
#else
//OSX, IOS
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_FREE);
#endif
#endif
printf("Freeing fpcb\n");
}
bool BM_LockedWrite(u8* address)
{
if (!_nvmem_enabled())
return false;
#if FEAT_SHREC != DYNAREC_NONE
u32 addr=address-(u8*)p_sh4rcb->fpcb;
address=(u8*)p_sh4rcb->fpcb+ (addr&~PAGE_MASK);
if (addr<sizeof(p_sh4rcb->fpcb))
{
//printf("Allocated %d PAGES [%08X]\n",++pagecnt,addr);
#if HOST_OS==OS_WINDOWS
verify(VirtualAlloc(address,PAGE_SIZE,MEM_COMMIT,PAGE_READWRITE));
#else
mprotect (address, PAGE_SIZE, PROT_READ | PROT_WRITE);
#endif
bm_vmem_pagefill((void**)address,PAGE_SIZE);
if (ptrint >= start && ptrint < end) {
// Alloc the page then and initialize it to default values
void *aligned_addr = (void*)(ptrint & (~PAGE_MASK));
vmem_platform_ondemand_page(aligned_addr, PAGE_SIZE);
bm_vmem_pagefill((void**)aligned_addr, PAGE_SIZE);
return true;
}
#else
die("BM_LockedWrite and NO REC");
#endif
return false;
}
bool _vmem_reserve()
{
void* ptr=0;
bool _vmem_reserve() {
// TODO: Static assert?
verify((sizeof(Sh4RCB)%PAGE_SIZE)==0);
if (settings.dynarec.disable_nvmem)
return _vmem_reserve_nonvmem();
VMemType vmemstatus = MemTypeError;
virt_ram_base=(u8*)_nvmem_alloc_mem();
// Use vmem only if settings mandate so, and if we have proper exception handlers.
#ifndef TARGET_NO_EXCEPTIONS
if (!settings.dynarec.disable_nvmem)
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
#endif
if (virt_ram_base==0)
return _vmem_reserve_nonvmem();
p_sh4rcb=(Sh4RCB*)virt_ram_base;
// Fallback to statically allocated buffers, this results in slow-ops being generated.
if (vmemstatus == MemTypeError) {
printf("Warning! nvmem is DISABLED (due to failure or not being built-in\n");
virt_ram_base = 0;
// Map the sh4 context but protect access to Sh4RCB.fpcb[]
#if HOST_OS==OS_WINDOWS
//verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE));
verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE,PAGE_NOACCESS));
// Allocate it all and initialize it.
p_sh4rcb = (Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
verify(VirtualAlloc((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),MEM_COMMIT,PAGE_READWRITE));
#else
verify(p_sh4rcb==mmap(p_sh4rcb,sizeof(Sh4RCB),PROT_NONE,MAP_PRIVATE | MAP_ANON, -1, 0));
mprotect((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),PROT_READ|PROT_WRITE);
#endif
virt_ram_base+=sizeof(Sh4RCB);
mem_b.size = RAM_SIZE;
mem_b.data = (u8*)malloc_pages(RAM_SIZE);
//Area 0
//[0x00000000 ,0x00800000) -> unused
unused_buffer(0x00000000,0x00800000);
vram.size = VRAM_SIZE;
vram.data = (u8*)malloc_pages(VRAM_SIZE);
//I wonder, aica ram warps here ?.?
//I really should check teh docs before codin ;p
//[0x00800000,0x00A00000);
map_buffer(0x00800000,0x01000000,MAP_ARAM_START_OFFSET,ARAM_SIZE,false);
map_buffer(0x20000000,0x20000000+ARAM_SIZE,MAP_ARAM_START_OFFSET,ARAM_SIZE,true);
aica_ram.size = ARAM_SIZE;
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
}
else {
printf("Info: nvmem is enabled, with addr space of size %s\n", vmemstatus == MemType4GB ? "4GB" : "512MB");
// Map the different parts of the memory file into the new memory range we got.
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
const vmem_mapping mem_mappings[] = {
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, false}, // Aica, wraps too
{0x20000000, 0x20000000+ARAM_SIZE, MAP_ARAM_START_OFFSET, ARAM_SIZE, true},
{0x01000000, 0x04000000, 0, 0, false}, // More unused
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
};
vmem_platform_create_mappings(&mem_mappings[0], sizeof(mem_mappings) / sizeof(mem_mappings[0]));
aica_ram.size=ARAM_SIZE;
aica_ram.data=(u8*)ptr;
//[0x01000000 ,0x04000000) -> unused
unused_buffer(0x01000000,0x04000000);
// Point buffers to actual data pointers
aica_ram.size = ARAM_SIZE;
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writtable AICA addrspace
//Area 1
//[0x04000000,0x05000000) -> vram (16mb, warped on dc)
map_buffer(0x04000000,0x05000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
vram.size=VRAM_SIZE;
vram.data=(u8*)ptr;
vram.size = VRAM_SIZE;
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writtable and lockable)
//[0x05000000,0x06000000) -> unused (32b path)
unused_buffer(0x05000000,0x06000000);
//[0x06000000,0x07000000) -> vram mirror
map_buffer(0x06000000,0x07000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
//[0x07000000,0x08000000) -> unused (32b path) mirror
unused_buffer(0x07000000,0x08000000);
//Area 2
//[0x08000000,0x0C000000) -> unused
unused_buffer(0x08000000,0x0C000000);
//Area 3
//[0x0C000000,0x0D000000) -> main ram
//[0x0D000000,0x0E000000) -> main ram mirror
//[0x0E000000,0x0F000000) -> main ram mirror
//[0x0F000000,0x10000000) -> main ram mirror
map_buffer(0x0C000000,0x10000000,MAP_RAM_START_OFFSET,RAM_SIZE,true);
mem_b.size=RAM_SIZE;
mem_b.data=(u8*)ptr;
//Area 4
//Area 5
//Area 6
//Area 7
//all -> Unused
//[0x10000000,0x20000000) -> unused
unused_buffer(0x10000000,0x20000000);
printf("vmem reserve: base: %08X, aram: %08x, vram: %08X, ram: %08X\n",virt_ram_base,aica_ram.data,vram.data,mem_b.data);
mem_b.size = RAM_SIZE;
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
}
// Clear out memory
aica_ram.Zero();
vram.Zero();
mem_b.Zero();
printf("Mem alloc successful!\n");
return virt_ram_base!=0;
return true;
}
void _vmem_release()
{
if (!_nvmem_enabled())
_vmem_release_nonvmem();
else
{
if (virt_ram_base != NULL)
{
#if HOST_OS == OS_WINDOWS
VirtualFree(virt_ram_base, 0, MEM_RELEASE);
#else
munmap(virt_ram_base, 0x20000000);
#endif
virt_ram_base = NULL;
}
#if HOST_OS != OS_WINDOWS
close(fd);
#endif
#define freedefptr(x) \
if (x) { free(x); x = NULL; }
void _vmem_release() {
if (virt_ram_base)
vmem_platform_destroy();
else {
freedefptr(p_sh4rcb);
freedefptr(vram.data);
freedefptr(aica_ram.data);
freedefptr(mem_b.data);
}
}
#else
bool _vmem_reserve()
{
return _vmem_reserve_nonvmem();
}
void _vmem_release()
{
_vmem_release_nonvmem();
}
#endif

View File

@ -1,6 +1,33 @@
#pragma once
#include "types.h"
enum VMemType {
MemType4GB,
MemType512MB,
MemTypeError
};
struct vmem_mapping {
u32 start_address, end_address;
unsigned memoffset, memsize;
bool allow_writes;
};
// Platform specific vmemory API
// To initialize (maybe) the vmem subsystem
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr);
// To reset the on-demand allocated pages.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes);
// To handle a fault&allocate an ondemand page.
void vmem_platform_ondemand_page(void *address, unsigned size_bytes);
// To create the mappings in the address space.
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps);
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy();
// Note: if you want to disable vmem magic in any given platform, implement the
// above functions as empty functions and make vmem_platform_init return MemTypeError.
//Typedef's
//ReadMem
typedef u8 DYNACALL _vmem_ReadMem8FP(u32 Address);
@ -70,4 +97,4 @@ static inline bool _nvmem_enabled() {
return virt_ram_base != 0;
}
void _vmem_bm_reset();
void _vmem_bm_reset();

View File

@ -9,7 +9,7 @@ f32 vrf(u32 addr);
u32 vri(u32 addr);
//vram 32-64b
extern VArray2 vram;
extern VLockedMemory vram;
//read
u8 DYNACALL pvr_read_area1_8(u32 addr);
u16 DYNACALL pvr_read_area1_16(u32 addr);
@ -36,4 +36,4 @@ extern "C" void DYNACALL TAWriteSQ(u32 address,u8* sqb);
void YUV_init();
//registers
#define PVR_BASE 0x005F8000
#define PVR_BASE 0x005F8000

View File

@ -339,9 +339,9 @@ void bm_Rebuild()
rebuild_counter=30;
}
void bm_vmem_pagefill(void** ptr,u32 PAGE_SZ)
void bm_vmem_pagefill(void** ptr, u32 size_bytes)
{
for (size_t i=0; i<PAGE_SZ/sizeof(ptr[0]); i++)
for (size_t i=0; i < size_bytes / sizeof(ptr[0]); i++)
{
ptr[i]=(void*)ngen_FailedToFindBlock;
}

View File

@ -17,7 +17,7 @@
//main system mem
VArray2 mem_b;
VLockedMemory mem_b;
void _vmem_init();
void _vmem_reset();

View File

@ -2,7 +2,7 @@
#include "types.h"
//main system mem
extern VArray2 mem_b;
extern VLockedMemory mem_b;
#include "hw/mem/_vmem.h"
#include "modules/mmu.h"

View File

@ -57,7 +57,6 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
}
#endif
#if !defined(TARGET_NO_EXCEPTIONS)
void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
{
rei_host_context_t ctx;
@ -108,12 +107,9 @@ void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
signal(SIGSEGV, SIG_DFL);
}
}
#endif
#endif
void install_fault_handler (void)
void install_fault_handler(void)
{
#if !defined(TARGET_NO_EXCEPTIONS)
struct sigaction act, segv_oact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = fault_handler;
@ -127,77 +123,14 @@ void install_fault_handler (void)
act.sa_sigaction = sigill_handler;
sigaction(SIGILL, &act, &segv_oact);
#endif
#endif
}
#else // !defined(TARGET_NO_EXCEPTIONS)
// No exceptions/nvmem dummy handlers.
void install_fault_handler(void) {}
#endif // !defined(TARGET_NO_EXCEPTIONS)
#include <errno.h>
void VArray2::LockRegion(u32 offset,u32 size)
{
#if !defined(TARGET_NO_EXCEPTIONS)
u32 inpage=offset & PAGE_MASK;
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ );
if (rv!=0)
{
printf("mprotect(%8s,%08X,R) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
die("mprotect failed ..\n");
}
#else
//printf("VA2: LockRegion\n");
#endif
}
void print_mem_addr()
{
FILE *ifp, *ofp;
char outputFilename[] = "/data/data/com.reicast.emulator/files/mem_alloc.txt";
ifp = fopen("/proc/self/maps", "r");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file /proc/self/maps!\n");
exit(1);
}
ofp = fopen(outputFilename, "w");
if (ofp == NULL) {
fprintf(stderr, "Can't open output file %s!\n",
outputFilename);
#if HOST_OS == OS_LINUX
ofp = stderr;
#else
exit(1);
#endif
}
char line [ 512 ];
while (fgets(line, sizeof line, ifp) != NULL) {
fprintf(ofp, "%s", line);
}
fclose(ifp);
if (ofp != stderr)
fclose(ofp);
}
void VArray2::UnLockRegion(u32 offset,u32 size)
{
#if !defined(TARGET_NO_EXCEPTIONS)
u32 inpage=offset & PAGE_MASK;
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ | PROT_WRITE);
if (rv!=0)
{
print_mem_addr();
printf("mprotect(%8p,%08X,RW) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
die("mprotect failed ..\n");
}
#else
//printf("VA2: UnLockRegion\n");
#endif
}
double os_GetSeconds()
{
timeval a;

178
core/linux/posix_vmem.cpp Normal file
View File

@ -0,0 +1,178 @@
// Implementation of the vmem related function for POSIX-like platforms.
// There's some minimal amount of platform specific hacks to support
// Android and OSX since they are slightly different in some areas.
// This implements the VLockedMemory interface, as defined in _vmem.h
// The implementation allows it to be empty (that is, to not lock memory).
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "hw/mem/_vmem.h"
#include "stdclass.h"
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
#endif
#ifdef _ANDROID
#include <linux/ashmem.h>
#ifndef ASHMEM_DEVICE
#define ASHMEM_DEVICE "/dev/ashmem"
#undef PAGE_MASK
#define PAGE_MASK (PAGE_SIZE-1)
#else
#define PAGE_SIZE 4096
#define PAGE_MASK (PAGE_SIZE-1)
#endif
// Android specific ashmem-device stuff for creating shared memory regions
int ashmem_create_region(const char *name, size_t size) {
int fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return -1;
if (ioctl(fd, ASHMEM_SET_SIZE, size) < 0) {
close(fd);
return -1;
}
return fd;
}
#endif // #ifdef _ANDROID
void VLockedMemory::LockRegion(unsigned offset, unsigned size_bytes) {
size_t inpage = offset & PAGE_MASK;
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ)) {
die("mprotect failed ..\n");
}
}
void VLockedMemory::UnLockRegion(unsigned offset, unsigned size_bytes) {
size_t inpage = offset & PAGE_MASK;
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ|PROT_WRITE)) {
// Add some way to see why it failed? gdb> info proc mappings
die("mprotect failed ..\n");
}
}
// Allocates memory via a fd on shmem/ahmem or even a file on disk
static int allocate_shared_filemem() {
int fd = -1;
#if defined(_ANDROID)
// Use Android's specific shmem stuff.
fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
#else
#if HOST_OS != OS_DARWIN
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
shm_unlink("/dcnzorz_mem");
#endif
// if shmem does not work (or using OSX) fallback to a regular file on disk
if (fd < 0) {
string path = get_writable_data_path("/dcnzorz_mem");
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
unlink(path.c_str());
}
// If we can't open the file, fallback to slow mem.
if (fd < 0)
return -1;
// Finally make the file as big as we need!
if (ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX)) {
// Can't get as much memory as needed, fallback.
close(fd);
return -1;
}
#endif
return fd;
}
// Implement vmem initialization for RAM, ARAM, VRAM and SH4 context, fpcb etc.
// The function supports allocating 512MB or 4GB addr spaces.
static int shmem_fd = -1;
// vmem_base_addr points to an address space of 512MB (or 4GB) that can be used for fast memory ops.
// In negative offsets of the pointer (up to FPCB size, usually 65/129MB) the context and jump table
// can be found. If the platform init returns error, the user is responsible for initializing the
// memory using a fallback (that is, regular mallocs and falling back to slow memory JIT).
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) {
// Firt let's try to allocate the shm-backed memory
shmem_fd = allocate_shared_filemem();
if (shmem_fd < 0)
return MemTypeError;
// Now try to allocate a contiguous piece of memory.
unsigned memsize = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
void *first_ptr = mmap(0, memsize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (!first_ptr) {
close(shmem_fd);
return MemTypeError;
}
// Align pointer to 64KB too, some Linaro bug (no idea but let's just be safe I guess).
uintptr_t ptrint = (uintptr_t)first_ptr;
ptrint = (ptrint + 0x10000 - 1) & (~0xffff);
*sh4rcb_addr = (void*)ptrint;
*vmem_base_addr = (void*)(ptrint + sizeof(Sh4RCB));
void *sh4rcb_base_ptr = (void*)(ptrint + FPCB_SIZE);
// Now map the memory for the SH4 context, do not include FPCB on purpose (paged on demand).
mprotect(sh4rcb_base_ptr, sizeof(Sh4RCB) - FPCB_SIZE, PROT_READ | PROT_WRITE);
return MemType512MB;
}
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy() {
munmap(virt_ram_base, 0x20000000);
}
// Resets a chunk of memory by deleting its data and setting its protection back.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes) {
// Mark them as non accessible.
mprotect(ptr, size_bytes, PROT_NONE);
// Tell the kernel to flush'em all (FIXME: perhaps unmap+mmap 'd be better?)
madvise(ptr, size_bytes, MADV_DONTNEED);
#if defined(MADV_REMOVE)
madvise(ptr, size_bytes, MADV_REMOVE);
#elif defined(MADV_FREE)
madvise(ptr, size_bytes, MADV_FREE);
#endif
}
// Allocates a bunch of memory (page aligned and page-sized)
void vmem_platform_ondemand_page(void *address, unsigned size_bytes) {
verify(!mprotect(address, size_bytes, PROT_READ | PROT_WRITE));
}
// Creates mappings to the underlying file including mirroring sections
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps) {
for (unsigned i = 0; i < nummaps; i++) {
// Ignore unmapped stuff, it is already reserved as PROT_NONE
if (!vmem_maps[i].memsize)
continue;
// Calculate the number of mirrors
unsigned address_range_size = vmem_maps[i].end_address - vmem_maps[i].start_address;
unsigned num_mirrors = (address_range_size) / vmem_maps[i].memsize;
int protection = vmem_maps[i].allow_writes ? (PROT_READ | PROT_WRITE) : PROT_READ;
verify((address_range_size % vmem_maps[i].memsize) == 0 && num_mirrors >= 1);
for (unsigned j = 0; j < num_mirrors; j++) {
unsigned offset = vmem_maps[i].start_address + j * vmem_maps[i].memsize;
verify(!munmap(&virt_ram_base[offset], vmem_maps[i].memsize));
verify(MAP_FAILED != mmap(&virt_ram_base[offset], vmem_maps[i].memsize, protection,
MAP_SHARED | MAP_NOSYNC | MAP_FIXED, shmem_fd, vmem_maps[i].memoffset));
// ??? (mprotect(rv,size,prot)!=0)
}
}
}

View File

@ -124,8 +124,7 @@ void palette_update()
using namespace std;
vector<vram_block*> VramLocks[VRAM_SIZE/PAGE_SIZE];
//vram 32-64b
VArray2 vram;
VLockedMemory vram; // vram 32-64b
//List functions
//
@ -207,7 +206,7 @@ vram_block* libCore_vramlock_Lock(u32 start_offset64,u32 end_offset64,void* user
{
vramlist_lock.Lock();
vram.LockRegion(block->start,block->len);
vram.LockRegion(block->start, block->len);
//TODO: Fix this for 32M wrap as well
if (_nvmem_enabled() && VRAM_SIZE == 0x800000) {

View File

@ -101,7 +101,7 @@ extern AicaTimer timers[3];
//./core/hw/aica/aica_if.o
extern VArray2 aica_ram;
extern VLockedMemory aica_ram;
extern u32 VREG;//video reg =P
extern u32 ARMRST;//arm reset reg
extern u32 rtc_EN;
@ -381,7 +381,7 @@ extern DECL_ALIGN(4) u32 SFaceOffsColor;
//extern vector<vram_block*> VramLocks[/*VRAM_SIZE*/(16*1024*1024)/PAGE_SIZE];
//maybe - probably not - just a locking mechanism
//extern cMutex vramlist_lock;
extern VArray2 vram;
extern VLockedMemory vram;
@ -403,7 +403,7 @@ extern Array<RegisterStruct> SCIF; //SCIF : 10 registers
//./core/hw/sh4/sh4_mem.o
extern VArray2 mem_b;
extern VLockedMemory mem_b;
//one-time init
//extern _vmem_handler area1_32b;
//one-time init

View File

@ -279,29 +279,38 @@ string get_game_save_prefix();
string get_game_basename();
string get_game_dir();
class VArray2
{
// Locked memory class, used for texture invalidation purposes.
class VLockedMemory {
public:
u8* data;
u32 size;
//void Init(void* data,u32 sz);
//void Term();
void LockRegion(u32 offset,u32 size);
void UnLockRegion(u32 offset,u32 size);
unsigned size;
void Zero()
{
UnLockRegion(0,size);
memset(data,0,size);
void SetRegion(void* ptr, unsigned size) {
this->data = (u8*)ptr;
this->size = size;
}
void *getPtr() const { return data; }
unsigned getSize() const { return size; }
#ifdef TARGET_NO_EXCEPTIONS
void LockRegion(unsigned offset, unsigned size_bytes) {}
void UnLockRegion(unsigned offset, unsigned size_bytes) {}
#else
void LockRegion(unsigned offset, unsigned size_bytes);
void UnLockRegion(unsigned offset, unsigned size_bytes);
#endif
void Zero() {
UnLockRegion(0, size);
memset(data, 0, size);
}
INLINE u8& operator [](const u32 i)
{
INLINE u8& operator [](unsigned i) {
#ifdef MEM_BOUND_CHECK
if (i>=size)
if (i >= size)
{
printf("Error: VArray2 , index out of range (%d>%d)\n",i,size-1);
printf("Error: VLockedMemory , index out of range (%d > %d)\n", i, size-1);
MEM_DO_BREAK;
}
#endif
@ -309,6 +318,7 @@ public:
}
};
int msgboxf(const wchar* text,unsigned int type,...);

104
core/windows/win_vmem.cpp Normal file
View File

@ -0,0 +1,104 @@
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <windowsx.h>
#include "hw/mem/_vmem.h"
// Implementation of the vmem related function for Windows platforms.
// For now this probably does some assumptions on the CPU/platform.
// This implements the VLockedMemory interface, as defined in _vmem.h
// The implementation allows it to be empty (that is, to not lock memory).
void VLockedMemory::LockRegion(unsigned offset, unsigned size) {
//verify(offset + size < this->size && size != 0);
DWORD old;
VirtualProtect(&data[offset], size, PAGE_READONLY, &old);
}
void VLockedMemory::UnLockRegion(unsigned offset, unsigned size) {
//verify(offset + size <= this->size && size != 0);
DWORD old;
VirtualProtect(&data[offset], size, PAGE_READWRITE, &old);
}
static HANDLE mem_handle = INVALID_HANDLE_VALUE;
static char * base_alloc = NULL;
// Implement vmem initialization for RAM, ARAM, VRAM and SH4 context, fpcb etc.
// The function supports allocating 512MB or 4GB addr spaces.
// Plase read the POSIX implementation for more information. On Windows this is
// rather straightforward.
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) {
// Firt let's try to allocate the in-memory file
mem_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX, 0);
// Now allocate the actual address space (it will be 64KB aligned on windows).
unsigned memsize = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX;
base_alloc = (char*)VirtualAlloc(0, memsize, MEM_RESERVE, PAGE_NOACCESS);
// Calculate pointers now
*sh4rcb_addr = &base_alloc[0];
*vmem_base_addr = &base_alloc[sizeof(Sh4RCB)];
return MemType512MB;
}
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy() {
VirtualFree(base_alloc, 0, MEM_RELEASE);
CloseHandle(mem_handle);
}
// Resets a chunk of memory by deleting its data and setting its protection back.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes) {
VirtualFree(ptr, size_bytes, MEM_DECOMMIT);
}
// Allocates a bunch of memory (page aligned and page-sized)
void vmem_platform_ondemand_page(void *address, unsigned size_bytes) {
verify(VirtualAlloc(address, size_bytes, MEM_COMMIT, PAGE_READWRITE));
}
/// Creates mappings to the underlying file including mirroring sections
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps) {
// Since this is tricky to get right in Windows (in posix one can just unmap sections and remap later)
// we unmap the whole thing only to remap it later.
// Unmap the whole section
VirtualFree(base_alloc, 0, MEM_RELEASE);
// Map the SH4CB block too
void *base_ptr = VirtualAlloc(base_alloc, sizeof(Sh4RCB), MEM_RESERVE, PAGE_NOACCESS);
verify(base_ptr == base_alloc);
void *cntx_ptr = VirtualAlloc((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb), sizeof(Sh4RCB) - sizeof(p_sh4rcb->fpcb), MEM_COMMIT, PAGE_READWRITE);
verify(cntx_ptr == (u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb));
for (unsigned i = 0; i < nummaps; i++) {
unsigned address_range_size = vmem_maps[i].end_address - vmem_maps[i].start_address;
DWORD protection = vmem_maps[i].allow_writes ? (FILE_MAP_READ | FILE_MAP_WRITE) : FILE_MAP_READ;
if (!vmem_maps[i].memsize) {
// Unmapped stuff goes with a protected area or memory. Prevent anything from allocating here
void *ptr = VirtualAlloc(&virt_ram_base[vmem_maps[i].start_address], address_range_size, MEM_RESERVE, PAGE_NOACCESS);
verify(ptr == &virt_ram_base[vmem_maps[i].start_address]);
}
else {
// Calculate the number of mirrors
unsigned num_mirrors = (address_range_size) / vmem_maps[i].memsize;
verify((address_range_size % vmem_maps[i].memsize) == 0 && num_mirrors >= 1);
// Remap the views one by one
for (unsigned j = 0; j < num_mirrors; j++) {
unsigned offset = vmem_maps[i].start_address + j * vmem_maps[i].memsize;
void *ptr = MapViewOfFileEx(mem_handle, protection, 0, vmem_maps[i].memoffset,
vmem_maps[i].memsize, &virt_ram_base[offset]);
verify(ptr == &virt_ram_base[offset]);
}
}
}
}

View File

@ -148,12 +148,10 @@ LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
#ifndef TARGET_NO_NVMEM
else if (BM_LockedWrite(address))
{
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif
#if FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86
else if ( ngen_Rewrite((unat&)ep->ContextRecord->Eip,*(unat*)ep->ContextRecord->Esp,ep->ContextRecord->Eax) )
{
@ -800,21 +798,5 @@ void os_DoEvents()
}
}
void VArray2::LockRegion(u32 offset,u32 size)
{
//verify(offset+size<this->size);
verify(size!=0);
DWORD old;
VirtualProtect(((u8*)data)+offset , size, PAGE_READONLY,&old);
}
void VArray2::UnLockRegion(u32 offset,u32 size)
{
//verify(offset+size<=this->size);
verify(size!=0);
DWORD old;
VirtualProtect(((u8*)data)+offset , size, PAGE_READWRITE,&old);
}
int get_mic_data(u8* buffer) { return 0; }
int push_vmu_screen(u8* buffer) { return 0; }

View File

@ -26,7 +26,7 @@ LDFLAGS := -Wl,-Map,$(notdir $@).map,--gc-sections -Wl,-O3 -Wl,--sort-common
CXXONLYFLAGS := -std=c++11
CXXFLAGS := -O3 -D GLES -D RELEASE -c -D TARGET_EMSCRIPTEN -D TARGET_NO_REC -D TARGET_NO_NVMEM -D TARGET_NO_WEBUI -D TARGET_NO_THREADS -D TARGET_BOUNDED_EXECUTION -D TARGET_NO_EXCEPTIONS -D TARGET_NO_COREIO_HTTP
CXXFLAGS := -O3 -D GLES -D RELEASE -c -D TARGET_EMSCRIPTEN -D TARGET_NO_REC -D TARGET_NO_EXCEPTIONS -D TARGET_NO_WEBUI -D TARGET_NO_THREADS -D TARGET_BOUNDED_EXECUTION -D TARGET_NO_COREIO_HTTP
CXXFLAGS += -fno-strict-aliasing
CXXFLAGS += -ffast-math

View File

@ -23,7 +23,7 @@ CFLAGS = -Wno-error -Wno-ignored-attributes
CFLAGS += -O3 -fno-strict-aliasing -ffast-math
CFLAGS += -I$(RZDCY_SRC_DIR) -I$(RZDCY_SRC_DIR)/deps
CFLAGS += -D RELEASE -D TARGET_NO_JIT -D TARGET_NACL32 -DGLES
CFLAGS += -D TARGET_NO_EXCEPTIONS -D TARGET_NO_NVMEM -D TARGET_NO_WEBUI -D TARGET_NO_COREIO_HTTP
CFLAGS += -D TARGET_NO_EXCEPTIONS -D TARGET_NO_WEBUI -D TARGET_NO_COREIO_HTTP
SOURCES = $(RZDCY_FILES) ../../core/nacl/nacl.cpp
@ -49,4 +49,4 @@ endif
SHELL = sh
$(eval $(call NMF_RULE,$(TARGET),))
$(eval $(call NMF_RULE,$(TARGET),))

View File

@ -322,6 +322,7 @@
<ClCompile Include="..\core\stdclass.cpp" />
<ClCompile Include="..\core\webui\server.cpp" />
<ClCompile Include="..\core\windows\winmain.cpp" />
<ClCompile Include="..\core\windows\win_vmem.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\core\archive\7zArchive.h" />
@ -998,4 +999,4 @@ for /f "delims=" %%i in ('date /T') do echo #define BUILD_DATE "%%i" &gt;&gt;$(P
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
</Project>

View File

@ -129,6 +129,9 @@
<ClCompile Include="..\core\windows\winmain.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="..\core\windows\win_vmem.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="..\core\profiler\profiler.cpp">
<Filter>profiler</Filter>
</ClCompile>
@ -1397,4 +1400,4 @@
<ItemGroup>
<MASM Include="..\core\rec-x64\msvc.asm" />
</ItemGroup>
</Project>
</Project>